﻿//===============================================================================
// Microsoft Innovation Centre - Western Europe
// Copyright (c) 2008 Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
//===============================================================================

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
using Microsoft.WVB.Framework;
using Microsoft.WVB.Framework.DataServicesEntities;
using Microsoft.WVB.Silverlight.Infrastructure;
using Microsoft.Practices.Composite.Events;
using Microsoft.WVB.Silverlight.Infrastructure.Events;
using Microsoft.Practices.Composite.Wpf.Events;


namespace Microsoft.WVB.UI
{
    public class PlayerModel: BaseController, IPlayerModel, IDisposable
    {
        private const int timelineOffset = 5;
        private const string captionMarkerType = "Caption";

        private bool IsTimelineLocked = false;

        public Boolean Muted
        {
            get { return _Muted; }
            set { _Muted = value; OnPropertyChanged("Muted"); }
        }
        private Boolean _Muted;

        public Boolean Paused
        {
            get { return _Paused; }
            set { _Paused = value; OnPropertyChanged("Paused"); }
        }
        private Boolean _Paused;

        public double Volume
        {
            get { return _Volume; }
            set { _Volume = value; OnPropertyChanged("Volume"); }
        }
        private double _Volume;

        public Boolean Buffering
        {
            get { return _Buffering; }
            set { _Buffering = value; OnPropertyChanged("Buffering"); }
        }
        private Boolean _Buffering;

        public Boolean IsFullScreen
        {
            get { return Application.Current.Host.Content.IsFullScreen; }
            set
            {
                Application.Current.Host.Content.IsFullScreen = value;
                OnPropertyChanged("IsFullScreen");
            }
        }

        public TimeSpan Position
        {
            get { return _Position; }
            set { _Position = value; OnPropertyChanged("Position"); }
        }
        private TimeSpan _Position;

        public TimeSpan Duration
        {
            get { return _Duration; }
            set { _Duration = value; OnPropertyChanged("Duration"); }
        }
        private TimeSpan _Duration;

        public Boolean Playing
        {
            get { return _Playing; }
            set { _Playing = value; OnPropertyChanged("Playing"); }
        }
        private Boolean _Playing;

        public Double DurationProgress
        {
            get { return _DurationProgress; }
            set { _DurationProgress = value; OnPropertyChanged("DurationProgress"); }
        }
        private Double _DurationProgress;

        public double DownloadProgress
        {
            get { return _DownloadProgress; }
            protected set { _DownloadProgress = value; OnPropertyChanged("DownloadProgress"); }
        }
        private double _DownloadProgress;

        public MediaElement DisplaySurface
        {
            get
            {
                return media;
            }
        }
        private MediaElement media;

        public Boolean CanSeek
        {
            get { return _CanSeek; }
            protected set { _CanSeek = value; OnPropertyChanged("CanSeek"); }
        }
        private Boolean _CanSeek = false;

        public Boolean CanInteract
        {
            get { return _CanInteract; }
            protected set { _CanInteract = value; OnPropertyChanged("CanInteract"); }
        }
        private Boolean _CanInteract = true;


        public String CaptionText
        {
            get { return _CaptionText; }
            set { _CaptionText = value; OnPropertyChanged("CaptionText"); }
        }
        private String _CaptionText;

        private DispatcherTimer timer = null;
        private double _defaultPlayerWidth = 0.0;
        private double _defaultPlayerHeight = 0.0;

        public PlayerModel()
        {
            media = new MediaElement();
            media.Stretch = System.Windows.Media.Stretch.Fill;
            media.VerticalAlignment = VerticalAlignment.Stretch;
            media.HorizontalAlignment = HorizontalAlignment.Stretch;
            media.BufferingTime = TimeSpan.FromSeconds(10);
            media.AutoPlay = true;
            media.Stretch = System.Windows.Media.Stretch.UniformToFill;

            media.BufferingProgressChanged += new RoutedEventHandler(media_BufferingProgressChanged);
            media.CurrentStateChanged += new RoutedEventHandler(media_CurrentStateChanged);
            media.DownloadProgressChanged += new RoutedEventHandler(media_DownloadProgressChanged);
            media.MarkerReached += new System.Windows.Media.TimelineMarkerRoutedEventHandler(media_MarkerReached);
            media.MediaEnded += new RoutedEventHandler(media_MediaEnded);
            media.MediaFailed += new EventHandler<ExceptionRoutedEventArgs>(media_MediaFailed);
            media.MediaOpened += new RoutedEventHandler(media_MediaOpened);
            media.SizeChanged += new SizeChangedEventHandler(media_SizeChanged);
          
            timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromMilliseconds(50);
            timer.Tick += new EventHandler(timer_Tick);

            IEventAggregator ag = IoC.GetCreate<IEventAggregator>();
            ag.GetEvent<ProgramChangedEvent>().Subscribe(this.SetProgram, Microsoft.Practices.Composite.Wpf.Events.ThreadOption.UIThread, true);

            Application.Current.Host.Content.FullScreenChanged += delegate(object sender, EventArgs e)
            {
                // the Model needs to be aware that the fullscreen mode can be exited by pressing ESC key!
                if (Application.Current.Host.Content.IsFullScreen == false)
                    this.IsFullScreen = false;
            };

            //CompositeSilverlightEvent<TopicDataEventArgs<Program>> evt = ag.GetEvent<CompositeSilverlightEvent<TopicDataEventArgs<Program>>>();
            //evt.Subscribe(
            //    x => {
            //        Program program = x.Value;
            //         if ((program != null) && (program.HighResolutionLink != null))
            //            media.Source = new Uri(program.HighResolutionLink, UriKind.Absolute);
            //        else if (program.LowResolutionLink != null)
            //            media.Source = new Uri(program.LowResolutionLink, UriKind.Absolute);
            //        else
            //            throw new WVBException("Verify that program has a HighResolutionLink being set in the Database", null);
            //    }
            //    , ThreadOption.UIThread, true, xx => xx.Topic == "SetProgram");

            //media.Source = new Uri("http://silverlight.services.live.com/68958/Figther%20Pilots/video.wmv");
        }

        //void Content_FullScreenChanged(object sender, EventArgs e)
        //{
        //    if (Application.Current.Host.Content.IsFullScreen == true)
        //    {
        //    }
        //    else
        //    {
        //        this.IsFullScreen = false;
        //    }
        //}
        public void SetProgram(Program program)
        {
            if ((program != null) && (program.HighResolutionLink != null))
                media.Source = new Uri(program.HighResolutionLink, UriKind.Absolute);
            else if (program.LowResolutionLink != null)
                media.Source = new Uri(program.LowResolutionLink, UriKind.Absolute);
            else
                throw new WVBException("Verify that program has a HighResolutionLink being set in the Database", null);
        }

        protected virtual void timer_Tick(object sender, EventArgs e)
        {
            // Change DurationProgress Value
            if ((media.CurrentState == System.Windows.Media.MediaElementState.Playing)
                || (media.CurrentState == System.Windows.Media.MediaElementState.Paused))
            {
                if ((Duration.TotalMilliseconds > 0) && (!IsTimelineLocked))
                {
                    this.DurationProgress = (media.Position.TotalMilliseconds / Duration.TotalMilliseconds);
                    this.Position = media.Position;
                }
            }
        }

        protected virtual void media_SizeChanged(object sender, SizeChangedEventArgs e)
        {
        }

        protected virtual void media_MediaOpened(object sender, RoutedEventArgs e)
        {
            this.Duration = media.NaturalDuration.TimeSpan;
            this.Position = media.Position;
            this.CanSeek = media.CanSeek;

            _defaultPlayerHeight = media.NaturalVideoHeight;
            _defaultPlayerWidth = media.NaturalVideoWidth;

            if (media.AutoPlay)
            {
                timer.Start();
                this.Playing = true;
                this.Volume = media.Volume;
            }

            IEventAggregator ag = IoC.GetCreate<IEventAggregator>();
            ag.GetEvent<MediaOpenedEvent>().Publish(media);

            //IoC.CurrentApplicationMediator.NotifyColleagues(Events.MessageTopics.MediaOpened, media);
        }

        protected virtual void media_MediaFailed(object sender, ExceptionRoutedEventArgs e)
        {
            // Implement a Error Message Box
        }

        protected virtual void media_MediaEnded(object sender, RoutedEventArgs e)
        {
            // Notify others ...
            this.Playing = false;
            
            if (timer.IsEnabled)
                timer.Stop();
        }

        protected virtual void media_MarkerReached(object sender, System.Windows.Media.TimelineMarkerRoutedEventArgs e)
        {
            // Notify Ads Player
            if (e.Marker.Type == PlayerModel.captionMarkerType)
            {
                this.CaptionText = e.Marker.Text;
            }
        }

        protected virtual void media_DownloadProgressChanged(object sender, RoutedEventArgs e)
        {
            // Update the UI
            this.DownloadProgress = media.DownloadProgress;
        }

        protected virtual void media_CurrentStateChanged(object sender, RoutedEventArgs e)
        {
            // Update some UI

            if (media.CurrentState == System.Windows.Media.MediaElementState.Buffering)
            {
                this.Buffering = true;                
            }

            if (media.CurrentState == System.Windows.Media.MediaElementState.Playing)
            {
                this.Buffering = false;
                if (!timer.IsEnabled)
                {
                    timer.Start();
                }
            }

            if ((media.CurrentState == System.Windows.Media.MediaElementState.Stopped) ||
                (media.CurrentState == System.Windows.Media.MediaElementState.Closed))
            {
                timer.Stop();
                this.Playing = false;
            }
        }

        protected virtual void media_BufferingProgressChanged(object sender, RoutedEventArgs e)
        {
            if (_Buffering && media.BufferingProgress == 1.0)
            {
                this.Buffering = false;
            }
            else if (!_Buffering && media.BufferingProgress > 0 &&  media.BufferingProgress < 1.0)
            {
                this.Buffering = true;
            } 
        }

        public virtual void Action(ActionBag actionBag)
        {
            switch (actionBag.Action)
            {
                case PlayerAction.DisableCommand:
                    {
                        this.CanSeek = false;
                        this.CanInteract = false;
                    }
                    break;
                case PlayerAction.DisableCommandAndPause:
                    {
                        this.CanSeek = false;
                        this.CanInteract = false;
                        media.Pause();
                        this.Playing = false;
                        this.Paused = true;
                    }
                    break;
                case PlayerAction.EnableCommand:
                    {
                        this.CanSeek = media.CanSeek;
                        this.CanInteract = media.CanPause;
                    }
                    break;
                case PlayerAction.EnableCommandAndPlay:
                    {
                        this.CanSeek = media.CanSeek;
                        this.CanInteract = media.CanPause;
                        media.Play();
                        this.Playing = true;
                        this.Paused = false;
                    }
                    break;
                case PlayerAction.AdjustVolume:
                    {
                        double volume = (double)actionBag.Param;
                        media.Volume = volume;
                    }
                    break;
                case PlayerAction.AdjustTimeline:
                    {
                        double timeline = (double)actionBag.Param;
                        IsTimelineLocked = true;

                        lock (media)
                        {
                            media.Position = TimeSpan.FromMilliseconds(media.NaturalDuration.TimeSpan.TotalMilliseconds * timeline);
                        }

                        IsTimelineLocked = false;
                    }
                    break;
                case PlayerAction.MoveBackward:
                    {
                        if (media.Position.TotalSeconds > timelineOffset)
                            media.Position -= TimeSpan.FromSeconds(timelineOffset);
                        else
                            media.Position = TimeSpan.Zero;
                    }
                    break;
                case PlayerAction.MoveForward:
                    {
                        if ((media.NaturalDuration.TimeSpan.TotalSeconds - media.Position.Seconds) > timelineOffset)
                            media.Position += TimeSpan.FromSeconds(timelineOffset);
                        else
                            media.Position = media.NaturalDuration.TimeSpan;
                    }
                    break;
                case PlayerAction.Mute:
                    {
                        media.IsMuted = true;
                    }
                    break;
                case PlayerAction.UnMute:
                    {
                        media.IsMuted = false;
                    }
                    break;
                case PlayerAction.NarrowView:
                    {
                       
                    }
                    break;
                case PlayerAction.Pause:
                    {
                        if (media.CurrentState == System.Windows.Media.MediaElementState.Playing)
                        {
                            media.Pause();
                            this.Playing = false;
                        }
                    }
                    break;
                case PlayerAction.Play:
                    {
                        if (media.CurrentState != System.Windows.Media.MediaElementState.Playing)
                        {
                            media.Play();
                            this.Playing = true;
                        }
                    }
                    break;
                case PlayerAction.Stop:
                    {
                        media.Stop();
                        this.Playing = false;
                    }
                    break;
                case PlayerAction.WideView:
                    {
                       
                    }
                    break;
            }
        }


        #region IDisposable Members

        public void Dispose()
        {
            media.BufferingProgressChanged -= new RoutedEventHandler(media_BufferingProgressChanged);
            media.CurrentStateChanged -= new RoutedEventHandler(media_CurrentStateChanged);
            media.DownloadProgressChanged -= new RoutedEventHandler(media_DownloadProgressChanged);
            media.MarkerReached -= new System.Windows.Media.TimelineMarkerRoutedEventHandler(media_MarkerReached);
            media.MediaEnded -= new RoutedEventHandler(media_MediaEnded);
            media.MediaFailed -= new EventHandler<ExceptionRoutedEventArgs>(media_MediaFailed);
            media.MediaOpened -= new RoutedEventHandler(media_MediaOpened);
            media.SizeChanged -= new SizeChangedEventHandler(media_SizeChanged);
            timer.Tick -= new EventHandler(timer_Tick);
        }

        #endregion
    }
}
